﻿using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint;
using Newtonsoft.Json;
namespace Easy.Chat
{
    public class ChatHub : Hub
    {
        private readonly static ConnectionMapping<string> w_connections = new ConnectionMapping<string>();

        private static List<Presence> w_onlineUsers = new List<Presence>();

        private void w_addOnlineUser(Presence myPresence)
        {
            w_onlineUsers.Add(myPresence);

        }

        private List<Presence> w_getOnlineUsers()
        {
            return w_onlineUsers;
        }

        private Presence w_getPresence(string loginName)
        {
            return w_onlineUsers.Where(p => p.UserName == loginName
                ).FirstOrDefault();
        }
        private void w_removePresense(Presence p)
        {
            w_onlineUsers.Remove(p);
        }



        public void SetStatus(string status)
        {
            SPUser currentUser = SPContext.Current.Web.CurrentUser;
            string myLoginName = Context.User.Identity.Name;

            Presence myPresence = w_getPresence(myLoginName);

            if (myPresence == null)
            {

                myPresence = new Presence()
                {
                    DisplayName = currentUser.Name,
                    LastUpdate = DateTime.Now,
                    Status = status,
                    UserName = myLoginName

                };

                lock (w_onlineUsers)
                {
                    w_addOnlineUser(myPresence);
                }
            }
            else
            {
                myPresence.Status = status;
            }


            var allMyConns = w_connections.GetConnections(myLoginName).ToArray();
            Clients.AllExcept(allMyConns).someoneOnline(myPresence);

        }

        public void CreateConver(string userName)
        {
            string myLoginName = Context.User.Identity.Name;
            Presence myPresence = w_getPresence(myLoginName);
            Presence hisPresence = w_getPresence(userName);

            Conversation existingConver = Conversation.Get(myLoginName, userName);
            if (existingConver == null)
            {
                Conversation newConver = new Conversation(userName, myLoginName);
                Conversation.Add(newConver);
                existingConver = newConver;
            }
            else
            {
                existingConver.InitMsg();
            }

            foreach (var connId in w_connections.GetConnections(myLoginName))
            {
                Clients.Client(connId).createdConver(existingConver);
            }
        }

        public void SendPM(string converIdStr, string message)
        {
            int converId = int.Parse(converIdStr);
            Conversation conver = Conversation.GetByID(converId);

            string myLoginName = Context.User.Identity.Name;
            Presence myPresence = w_getPresence(myLoginName);
            DateTime now = DateTime.Now;
            PMessage pm = new PMessage()
            {

                From = myPresence,
                Message = message,
                When = now,
                ConverID = converId
            };

            PMessage.Add(pm);
            List<string> recipients = conver.GetAllOtherNames(myLoginName);
            foreach (string recipient in recipients)
            {
                foreach (var connId in w_connections.GetConnections(recipient))
                {
                    Clients.Client(connId).receivePM(pm);
                }
            }
        }

        public void SendAckPM(string msgId)
        {
            PMessage sentMsg = PMessage.GetByID(int.Parse(msgId));
            foreach (var connId in w_connections.GetConnections(sentMsg.From.UserName))
            {
                Clients.Client(connId).sentPM(sentMsg);
            }
        }

        public void SendLastSeen(int converId)
        {
            string myLoginName = Context.User.Identity.Name;
            Conversation conver = Conversation.GetByID(converId);
            conver.InitMsg();
            var lastPM = conver.PM.OrderBy(o => o.ID).Where(p => p.From.UserName != myLoginName).LastOrDefault();
            if (lastPM != null)
            {

                List<string> recipients = conver.GetAllOtherNames(myLoginName);
                foreach (string recipient in recipients)
                {
                    foreach (var connId in w_connections.GetConnections(recipient))
                    {
                        Clients.Client(connId).receivedLastSeen(lastPM.ID, converId);
                    }
                }
            }

        }

        public void SendTyping(int converId)
        {
            string myLoginName = Context.User.Identity.Name;
            Conversation conver = Conversation.GetByID(converId);
            List<string> recipients = conver.GetAllOtherNames(myLoginName);
            foreach (string recipient in recipients)
            {
                foreach (var connId in w_connections.GetConnections(recipient))
                {
                    Clients.Client(connId).receivedTyping(converId);
                }
            }
        }

        public void CancelTyping(int converId)
        {
            string myLoginName = Context.User.Identity.Name;
            Conversation conver = Conversation.GetByID(converId);
            List<string> recipients = conver.GetAllOtherNames(myLoginName);
            foreach (string recipient in recipients)
            {
                foreach (var connId in w_connections.GetConnections(recipient))
                {
                    Clients.Client(connId).cenceledTyping(converId);
                }
            }
        }


        public void GetOnlineUsers()
        {
            var presences = w_getOnlineUsers();
            var allExceptMe = presences.Where(u => u.UserName != Context.User.Identity.Name);

            Clients.Client(Context.ConnectionId).setOnlineUsers(allExceptMe);

        }


        public override Task OnConnected()
        {
            w_connections.Add(Context.User.Identity.Name, Context.ConnectionId);
            Clients.Client(Context.ConnectionId).connected(Context.User.Identity.Name);
            return base.OnConnected();
        }

        public override Task OnDisconnected(bool stopCalled)
        {
            string loginName = Context.User.Identity.Name;
            w_connections.Remove(loginName, Context.ConnectionId);

            var connIds = w_connections.GetConnections(loginName);
            if(connIds.Count() == 0)
            {
                Presence hisPresence = w_getPresence(loginName);
                hisPresence.Status = "Offline";
                Clients.All.someoneOnline(hisPresence);
                w_removePresense(hisPresence);
            }

            return base.OnDisconnected(stopCalled);
        }

        public override Task OnReconnected()
        {
            string name = Context.User.Identity.Name;

            if (!w_connections.GetConnections(name).Contains(Context.ConnectionId))
            {
                w_connections.Add(name, Context.ConnectionId);
            }

            return base.OnReconnected();
        }
    }
}
